package ch.ethz.inf.vs.sunspot.commons;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Random;

/**
 * A class providing general utilities like a RNG, ip -> location resolution,... 
 * 
 * @author Simon Mayer, ETH Zurich
 */
public class Utilities {
	
	/**
	 * Sends an HTTP GET request to a URL.
	 *
	 * @param endpoint - The URL of the server. (Example: " http://www.yahoo.com/search").
	 * @param requestParameters - All the request parameters (Example: "param1=val1&param2=val2"). Note: This method will add the question mark (?) to the request - DO NOT add it yourself.
	 * @return The response from the end point.
	 */
	public static String sendGetRequest(String endpoint, String requestParameters)
	{
		String result = null;
		if (endpoint.startsWith("http://"))
		{
			// Send a GET request to the servlet
			try
			{
				// Construct data
				//StringBuffer data = new StringBuffer();

				// Send data
				String urlStr = endpoint;
				if (requestParameters != null && requestParameters.length () > 0)
				{
					urlStr += "?" + requestParameters;
				}
				URL url = new URL(urlStr);
				URLConnection conn = url.openConnection ();
				
				conn.setRequestProperty("Accept", "text/json");

				// Get the response
				BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
				StringBuffer sb = new StringBuffer();
				String line;
				while ((line = rd.readLine()) != null)
				{
					sb.append(line);
				}
				rd.close();
				result = sb.toString();
			} catch (Exception e)
			{
				// System.out.println("GET: " + e.getMessage() + " on URL " + endpoint);
				
				if (!e.getMessage().contains("Connection refused")) {
					try {
						Thread.sleep(20);
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
				}
			}
		}
		return result;
	}
	
	/**
	 * Sends data via a HTTP PUT request to the given URL.
	 * @param dataString
	 * @param urlString
	 * @return The response
	 */
	public static String putStringToURL(String dataString, String urlString) {
		Writer output = new StringWriter();
		Reader data = new StringReader(dataString);

		URL url;
		try {
			url = new URL(urlString);
			Utilities.sendDataToURL(data, url, output, "PUT");
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		return output.toString();
	}
	
	/**
	 * Sends data via HTTP to a certain URL.
	 * @param data
	 * @param endpoint
	 * @param output
	 * @param requestMethod
	 * @throws Exception
	 */
	public static void sendDataToURL(Reader data, URL endpoint, Writer output, String requestMethod) throws Exception
	{
		HttpURLConnection urlc = null;
		try
		{
			urlc = (HttpURLConnection) endpoint.openConnection();
			try
			{
				urlc.setRequestMethod(requestMethod);
			} catch (ProtocolException e)
			{
				throw new Exception("Shouldn't happen: HttpURLConnection doesn't support POST??", e);
			}
			urlc.setDoOutput(true);
			urlc.setDoInput(true);
			urlc.setUseCaches(false);
			urlc.setAllowUserInteraction(false);
			urlc.setRequestProperty("Content-type", "application/xml; charset=" + "UTF-8");

			OutputStream out = urlc.getOutputStream();

			try
			{
				Writer writer = new OutputStreamWriter(out, "UTF-8");
				pipe(data, writer);
				writer.close();
			} catch (IOException e)
			{
				throw new Exception("IOException while posting data", e);
			} finally
			{
				if (out != null)
					out.close();
			}

			InputStream in = urlc.getInputStream();
			try
			{
				Reader reader = new InputStreamReader(in);
				pipe(reader, output);
				reader.close();
			} catch (IOException e)
			{
				throw new Exception("IOException while reading response", e);
			} finally
			{
				if (in != null)
					in.close();
			}

		} catch (IOException e)
		{
			// throw new Exception("Connection error (is server running at " + endpoint + " ?): " + e);
		} finally
		{
			if (urlc != null)
				urlc.disconnect();
		}
	}
	
	/**
	 * Pipes everything from the reader to the writer via a buffer
	 */
	private static void pipe(Reader reader, Writer writer) throws IOException
	{
		char[] buf = new char[1024];
		int read = 0;
		while ((read = reader.read(buf)) >= 0)
		{
			writer.write(buf, 0, read);
		}
		writer.flush();
	}
	
	/**
	 * A random number generator
	 */
	private static Random rng = null;
	
	/**
	 * Wraps Random.nextInt()
	 * 
	 * @return next integer
	 */
	public static Integer nextRandomInteger() {
		if (rng == null) rng = new Random(System.currentTimeMillis());
		return rng.nextInt();
	}
	
	/**
	 * Wraps Random.nextInt(n)
	 * 
	 * @param n
	 * @return next integer
	 */
	public static Integer nextRandomInteger(int n) {
		if (rng == null) rng = new Random(System.currentTimeMillis());
		return rng.nextInt(n);
	}
}